package com.dyp.securitydemo.config;
import com.dyp.securitydemo.security.jwt.JWTFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;

/**
 * 在Spring Security 5.7.0-M2中，Spring就废弃了WebSecurityConfigurerAdapter，因为Spring官方鼓励用户转向基于组件的安全配置。
 * https://blog.csdn.net/shenchaohao12321/article/details/87355803
 * https://blog.csdn.net/chisuisi5702/article/details/126281839
 *
 *
 * org.springframework.security.config.annotation.web.builders.HttpSecurity类中定义如下Filter List成员变量
 * private FilterOrderRegistration filterOrders = new FilterOrderRegistration();该变量设置了很多Spring默认的Filter
 * FilterOrderRegistration() {
 * 		Step order = new Step(INITIAL_ORDER, ORDER_STEP);
 * 		put(DisableEncodeUrlFilter.class, order.next());
 * 		put(ForceEagerSessionCreationFilter.class, order.next());
 * 		put(ChannelProcessingFilter.class, order.next());
 * 		order.next(); // gh-8105
 * 		put(WebAsyncManagerIntegrationFilter.class, order.next());
 * 		put(SecurityContextHolderFilter.class, order.next());
 * 		put(SecurityContextPersistenceFilter.class, order.next());
 * 		put(HeaderWriterFilter.class, order.next());
 * 		put(CorsFilter.class, order.next());
 * 		put(CsrfFilter.class, order.next());
 * 		put(LogoutFilter.class, order.next());
 * 		this.filterToOrder.put(
 * 				"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
 * 				order.next());
 * 		this.filterToOrder.put(
 * 				"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
 * 				order.next());
 * 		put(X509AuthenticationFilter.class, order.next());
 * 		put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
 * 		this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
 * 		this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
 * 				order.next());
 * 		this.filterToOrder.put(
 * 				"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
 * 				order.next());
 * 		put(UsernamePasswordAuthenticationFilter.class, order.next());
 * 		order.next(); // gh-8105
 * 		this.filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
 * 		put(DefaultLoginPageGeneratingFilter.class, order.next());
 * 		put(DefaultLogoutPageGeneratingFilter.class, order.next());
 * 		put(ConcurrentSessionFilter.class, order.next());
 * 		put(DigestAuthenticationFilter.class, order.next());
 * 		this.filterToOrder.put(
 * 				"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter",
 * 				order.next());
 * 		put(BasicAuthenticationFilter.class, order.next());
 * 		put(RequestCacheAwareFilter.class, order.next());
 * 		put(SecurityContextHolderAwareRequestFilter.class, order.next());
 * 		put(JaasApiIntegrationFilter.class, order.next());
 * 		put(RememberMeAuthenticationFilter.class, order.next());
 * 		put(AnonymousAuthenticationFilter.class, order.next());
 * 		this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
 * 				order.next());
 * 		put(SessionManagementFilter.class, order.next());
 * 		put(ExceptionTranslationFilter.class, order.next());
 * 		put(FilterSecurityInterceptor.class, order.next());
 * 		put(AuthorizationFilter.class, order.next());
 * 		put(SwitchUserFilter.class, order.next());
 *        }
 *
 */

@EnableWebSecurity
//prePostEnabled属性决定Spring Security在接口前注解是否可用@PreAuthorize,@PostAuthorize等注解,设置为true,会拦截加了这些注解的接口
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
// for SecurityProblemSupport object auto inject
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration  {
    BasicAuthenticationFilter basicAuthenticationFilter;
    UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter;

    HttpSecurity filterOrderRegistration;
    DefaultSecurityFilterChain defaultSecurityFilterChain;
    AccessDecisionManager accessDecisionManager;
    AuthenticationManager al;

    DaoAuthenticationProvider daoAuthenticationProvider;

    UserDetailsService userDetailsService;

    InMemoryUserDetailsManager userSerivce; //是 Spring Security 内置的 UserDetailsService 的实现类之一
    private final SecurityProblemSupport problemSupport;

    public SecurityConfiguration(SecurityProblemSupport problemSupport) {
        this.problemSupport = problemSupport;
    }

    // 注册SecurityFilterChain Bean，并完成HttpSecurity配置
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // @formatter:off
        http
                //去掉不用的filter
                .httpBasic().disable()
                .csrf().disable()
                .formLogin().disable()
                .logout().disable()
                .exceptionHandling()
                    .authenticationEntryPoint(problemSupport) //是在用户认证的时候出现错误时抛出的异常
                    .accessDeniedHandler(problemSupport) //主要是在用户在访问受保护资源时被拒绝而抛出的异常。
            .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/swagger-ui/**").permitAll()
//                .antMatchers("/user/**").permitAll()
                .antMatchers("/user/**").hasAuthority("ROLE_ADMIN")
                .antMatchers("/management/**").hasAuthority("ROLE_ADMIN")

            .and()
                .addFilterBefore(new JWTFilter(),UsernamePasswordAuthenticationFilter.class);


        return http.build();
        // @formatter:on
    }
    /**
     * 指定加密方式
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }
}
